package service

import (
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/gitee-go/core"
	"gitee.com/gitee-go/core/common"
	"gitee.com/gitee-go/core/model/pipeline"
	"gitee.com/gitee-go/core/runtime"
	"gitee.com/gitee-go/server/comm"
	"gitee.com/gitee-go/server/comm/hook"
	"gitee.com/gitee-go/server/comm/hook/gitee"
	"gitee.com/gitee-go/utils"
	"github.com/go-git/go-git/v5/plumbing"
	"net/http"
)

// webhook请求解析转换
func Parse(req *http.Request, hookType string) (*runtime.PreBuild, error) {
	fn := func(webhook hook.WebHook) (string, error) {
		repository := webhook.Repository()
		repo := new(pipeline.TRepo)
		db := comm.DBMain.GetDB()
		ok, err := db.
			Where("openid=? and deleted != 1 and active != 0",
				repository.RepoOpenid).
			Get(repo)
		if err != nil {
			return "", err
		}
		if !ok {
			return "", errors.New("仓库不存在! ")
		}
		return repo.HookSecret, nil
	}
	h, err := parseHook(hookType, req, fn)
	if err != nil {
		return nil, err
	}
	var pb *runtime.PreBuild
	switch c := h.(type) { //不同类型的hook
	case *hook.PullRequestHook:
		pb = &runtime.PreBuild{
			TriggerType: common.TRIGGER_TYPE_WEBHOOK,
			Info: &runtime.PreInfo{
				Action:            c.Action,
				Events:            common.EVENTS_TYPE_PR,
				PipelineId:        "",
				PipelineVersionId: "",
				Title:             c.PullRequest.Title,
				PrNumber:          c.PullRequest.Number,
				User: &runtime.PreUser{
					UserName: c.PullRequest.Author.UserName,
				},
				Note:          "",
				CommitMessage: "",
				Repository: &runtime.PreRepository{
					Id:          c.Repository().Id,
					Ref:         plumbing.NewBranchReferenceName(c.Repo.Ref).String(),
					Sha:         c.Repo.Sha,
					CloneURL:    c.Repo.CloneURL,
					CreatedAt:   c.Repo.CreatedAt,
					Branch:      c.Repo.Ref,
					Description: c.Repo.Description,
					FullName:    c.Repo.FullName,
					GitSvnURL:   c.Repo.GitSvnURL,
					GitURL:      c.Repo.GitURL,
					SvnURL:      c.Repo.SvnURL,
					Name:        c.Repo.Name,
					Private:     c.Repo.Private,
					URL:         c.Repo.URL,
					Owner:       c.Repo.Owner,
					RepoType:    hookType,
					RepoOpenid:  c.Repo.RepoOpenid,
				},
				TargetRepository: &runtime.PreRepository{
					Ref:         plumbing.NewBranchReferenceName(c.TargetRepo.Ref).String(),
					Sha:         c.TargetRepo.Sha,
					CloneURL:    c.TargetRepo.CloneURL,
					CreatedAt:   c.TargetRepo.CreatedAt,
					Branch:      c.TargetRepo.Ref,
					Description: c.TargetRepo.Description,
					FullName:    c.TargetRepo.FullName,
					GitSvnURL:   c.TargetRepo.GitSvnURL,
					GitURL:      c.TargetRepo.GitURL,
					SvnURL:      c.TargetRepo.SvnURL,
					Name:        c.TargetRepo.Name,
					Private:     c.TargetRepo.Private,
					URL:         c.TargetRepo.URL,
					Owner:       c.TargetRepo.Owner,
					RepoType:    hookType,
					RepoOpenid:  "",
				},
			},
		}
	case *hook.PullRequestCommentHook:
		pb = &runtime.PreBuild{
			TriggerType: common.TRIGGER_TYPE_WEBHOOK,
			Info: &runtime.PreInfo{
				Action:            c.Action,
				Events:            common.GITEE_EVENT_PR_ACTION_COMMENT,
				PipelineId:        "",
				PipelineVersionId: "",
				User: &runtime.PreUser{
					UserName: c.PullRequest.Author.UserName,
				},
				Title:         c.PullRequest.Title,
				PrNumber:      c.PullRequest.Number,
				Note:          c.Comment.Body,
				CommitMessage: "",
				Repository: &runtime.PreRepository{
					Id:          c.Repository().Id,
					Ref:         plumbing.NewBranchReferenceName(c.Repo.Ref).String(),
					Sha:         c.Repo.Sha,
					CloneURL:    c.Repo.CloneURL,
					CreatedAt:   c.Repo.CreatedAt,
					Branch:      c.Repo.Ref,
					Description: c.Repo.Description,
					FullName:    c.Repo.FullName,
					GitSvnURL:   c.Repo.GitSvnURL,
					GitURL:      c.Repo.GitURL,
					SvnURL:      c.Repo.SvnURL,
					Name:        c.Repo.Name,
					Private:     c.Repo.Private,
					URL:         c.Repo.URL,
					Owner:       c.Repo.Owner,
					RepoType:    hookType,
					RepoOpenid:  c.Repo.RepoOpenid,
				},
				TargetRepository: &runtime.PreRepository{
					Ref:         plumbing.NewBranchReferenceName(c.TargetRepo.Ref).String(),
					Sha:         c.TargetRepo.Sha,
					CloneURL:    c.TargetRepo.CloneURL,
					CreatedAt:   c.TargetRepo.CreatedAt,
					Description: c.TargetRepo.Description,
					FullName:    c.TargetRepo.FullName,
					GitSvnURL:   c.TargetRepo.GitSvnURL,
					GitURL:      c.TargetRepo.GitURL,
					SvnURL:      c.TargetRepo.SvnURL,
					Name:        c.TargetRepo.Name,
					Private:     c.TargetRepo.Private,
					URL:         c.TargetRepo.URL,
					Owner:       c.TargetRepo.Owner,
					RepoType:    hookType,
					RepoOpenid:  "",
				},
			},
		}
	case *hook.PushHook:
		pb = &runtime.PreBuild{
			TriggerType: common.TRIGGER_TYPE_WEBHOOK,
			Info: &runtime.PreInfo{
				Events:            common.EVENTS_TYPE_PUSH,
				PipelineId:        "",
				PipelineVersionId: "",
				User: &runtime.PreUser{
					UserName: c.Sender.UserName,
				},
				Note:          "",
				CommitMessage: c.Commit.Message,
				Repository: &runtime.PreRepository{
					Id:          c.Repository().Id,
					Ref:         c.Ref,
					Sha:         c.After,
					CloneURL:    c.Repo.CloneURL,
					CreatedAt:   c.Repo.CreatedAt,
					Branch:      c.Repo.Branch,
					Description: c.Repo.Description,
					FullName:    c.Repo.FullName,
					GitSvnURL:   c.Repo.GitSvnURL,
					GitURL:      c.Repo.GitURL,
					SvnURL:      c.Repo.SvnURL,
					Name:        c.Repo.Name,
					Private:     c.Repo.Private,
					URL:         c.Repo.URL,
					Owner:       c.Repo.Owner,
					RepoType:    hookType,
					RepoOpenid:  c.Repo.RepoOpenid,
				},
			},
		}
	default:
		return nil, errors.New("Build Parse Failed ")
	}
	marshal, err := json.Marshal(pb)
	if err != nil {
		return nil, err
	}
	repository := h.Repository()
	repo, b := checkRepo(repository)
	if !b {
		return nil, fmt.Errorf("%v 仓库不存在", repository.Name)
	}
	pb.Info.Repository.Id = repo.Id
	th := &pipeline.THook{
		Id:       utils.NewXid(),
		HookType: req.Header.Get(common.GITEE_EVENT),
		Type:     common.GITEE,
		Snapshot: string(marshal),
		Status:   common.PIPELINE_VERSION_STATUS_OK,
		Msg:      "",
	}
	db := comm.DBMain.GetDB()
	_, err = db.Insert(th)
	if err != nil {
		return nil, err
	}
	core.Log.Debugf("Parse preBuild %s ", string(marshal))
	return pb, nil
}

// 解析hook
func parseHook(hookType string, req *http.Request, fn hook.SecretFunc) (hook.WebHook, error) {
	switch hookType {
	case common.SourceGitee:
		return gitee.Parse(req, fn)
	default:
		return nil, fmt.Errorf("未知的webhook类型")
	}
}

func checkRepo(rp hook.Repository) (*pipeline.TRepo, bool) {
	repo := new(pipeline.TRepo)
	db := comm.DBMain.GetDB()
	ok, err := db.
		Where("openid=? and deleted != 1 and active != 0",
			rp.RepoOpenid).
		Get(repo)
	if err != nil {
		core.Log.Errorf("gitee Parse checkRepo db err:%v", err)
		return nil, false
	}
	return repo, ok
}
